package qf.common.security.utils;

import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import qf.common.core.web.vo.AjaxResult;
import qf.common.redis.constant.RedisConstant;
import qf.common.redis.utils.RedisUtil;
import qf.common.security.entitiy.SecuriyUserDetailVO;
import qf.common.security.entitiy.SysUser;
import qf.common.security.service.SecuritySysUserService;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Title: SecurityUtils
 * @Author itmei
 * @Package qf.common.security.utils
 * @Date 2023/3/1 21:27
 * @description: 手动认证流程
 */
@Component
public class SecurityUtils {

    private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private SecuritySysUserService userService;


    /**
     * 通过账户密码授权
     * @param userName
     * @param password
     * @return
     */
    public AjaxResult oAuthPassword(String userName,String password) {
        if (ObjectUtils.isEmpty(userName) || ObjectUtils.isEmpty(password)) {
            return AjaxResult.error("参数不全");
        }
        Authentication authenticate;
        try {
            //使用Authentication的实现类
            Authentication authentication = new UsernamePasswordAuthenticationToken(userName, password);
            //手动调用方法去认证 他会自动调用UserDetailsService查 然后对比啥的
            authenticate = authenticationManager.authenticate(authentication);
        }catch (Exception e) {
            LOG.error("授权失败，失败原因：" + e.getMessage());
            return AjaxResult.error("用户名或密码错误");
        }
        //拿到用户信息 然后生成jwt返回给前端，并且将用户的信息存入redis
        try {
            SecuriyUserDetailVO securiyUserDetailVO = (SecuriyUserDetailVO) authenticate.getPrincipal(); // 这个其实就是UserDetails 也就是LoginUser
            String userId = securiyUserDetailVO.getUser().getId().toString();

            Map<String, String> map = new HashMap<>();
            String jwt = JwtUtil.createJWT(userId);

            redisUtil.set(RedisConstant.USER_LOGIN_KEY+ userId, JSONObject.toJSONString(securiyUserDetailVO),RedisConstant.OAUTH_TOKEN_EXPIRE_TIME);//将用户信息直接存入redis 2小时

            map.put("token", jwt);

            return AjaxResult.success(map);
        }catch (Exception e) {
            return AjaxResult.error("系统异常,请稍后再试");
        }
    }

    /**
     * 通过密钥信息授权
     * @param busiNo
     * @param secretKey
     * @return
     */
    public AjaxResult oAuthSecretKey(String busiNo,String secretKey) {
        if (ObjectUtils.isEmpty(busiNo) || ObjectUtils.isEmpty(secretKey)) {
            return AjaxResult.error("参数不全");
        }
        // 补全内容
        AjaxResult result = userService.loginUserByBusiNoAndSecretkey(busiNo,secretKey);

        if (!result.isSuccess()) {
            return AjaxResult.error(result.getResultMsg());
        }
        SysUser sysUser = JSONObject.parseObject(JSONObject.toJSONString(result.getResultData()),SysUser.class);
        if (Objects.isNull(sysUser)) {
            return AjaxResult.error("密钥不正确");
        }
        return oAuthPassword(sysUser.getUserName(),sysUser.getPassword());
    }

    /**
     * 退出登录
     * @return
     */
    public AjaxResult logout() {
        //因为这个方法 是通过了jwt过滤器执行到这里的 所以SecurityContextHolder上下文是一样的
        SecuriyUserDetailVO securiyUserDetailVO = (SecuriyUserDetailVO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //拿到用户id删除redis中的数据
        String userId  = securiyUserDetailVO.getUser().getId().toString();
        if (redisUtil.del(RedisConstant.USER_LOGIN_KEY +userId)) {
            return AjaxResult.success();
        } else {
            return AjaxResult.error();
        }
    }


}
